package com.icongyou.enterprise.talent_analysis.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.icongyou.enterprise.talent_analysis.entity.HrTemplatePreference;
import com.icongyou.enterprise.talent_analysis.event.TemplateChangeEvent;
import com.icongyou.enterprise.talent_analysis.mapper.HrTemplatePreferenceMapper;
import com.icongyou.enterprise.talent_analysis.service.impl.HrTemplatePreferenceServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationEventPublisher;

import java.time.LocalDateTime;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

/**
 * HR模板偏好服务测试
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("HR模板偏好服务测试")
class HrTemplatePreferenceServiceImplTest {

    @Mock
    private HrTemplatePreferenceMapper preferenceMapper;

    @Mock
    private ApplicationEventPublisher eventPublisher;

    @InjectMocks
    private HrTemplatePreferenceServiceImpl preferenceService;

    private HrTemplatePreference preference;

    @BeforeEach
    void setUp() {
        preference = new HrTemplatePreference();
        preference.setId("pref-1");
        preference.setHrUserId("hr-1001");
        preference.setEnterpriseId("ent-1");
        preference.setTemplateId("tmpl-2001");
        preference.setLastUsedAt(LocalDateTime.now());
        preference.setCreatedAt(LocalDateTime.now());
        preference.setUpdatedAt(LocalDateTime.now());
    }

    @Test
    @DisplayName("获取当前模板ID - 有偏好记录")
    void testGetCurrentTemplateId_WithPreference() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);

        // When
        String templateId = preferenceService.getCurrentTemplateId("hr-1001");

        // Then
        assertNotNull(templateId);
        assertEquals("tmpl-2001", templateId);
        verify(preferenceMapper).selectByHrUserId("hr-1001");
    }

    @Test
    @DisplayName("获取当前模板ID - 无偏好记录返回null")
    void testGetCurrentTemplateId_NoPreference() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-9999")).thenReturn(null);

        // When
        String templateId = preferenceService.getCurrentTemplateId("hr-9999");

        // Then
        assertNull(templateId);
        verify(preferenceMapper).selectByHrUserId("hr-9999");
    }

    @Test
    @DisplayName("获取当前模板ID - 使用默认模板")
    void testGetCurrentTemplateId_DefaultTemplate() {
        // Given
        preference.setTemplateId(null);
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);

        // When
        String templateId = preferenceService.getCurrentTemplateId("hr-1001");

        // Then
        assertNull(templateId);
        verify(preferenceMapper).selectByHrUserId("hr-1001");
    }

    @Test
    @DisplayName("设置当前模板 - 首次设置（插入）")
    void testSetCurrentTemplate_FirstTime() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(null);
        when(preferenceMapper.insert(any(HrTemplatePreference.class))).thenReturn(1);

        // When
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-2001");

        // Then
        ArgumentCaptor<HrTemplatePreference> captor = ArgumentCaptor.forClass(HrTemplatePreference.class);
        verify(preferenceMapper).selectByHrUserId("hr-1001");
        verify(preferenceMapper).insert(captor.capture());
        
        HrTemplatePreference saved = captor.getValue();
        assertEquals("hr-1001", saved.getHrUserId());
        assertEquals("ent-1", saved.getEnterpriseId());
        assertEquals("tmpl-2001", saved.getTemplateId());
        assertNotNull(saved.getId());
        assertNotNull(saved.getCreatedAt());
        assertNotNull(saved.getUpdatedAt());
        assertNotNull(saved.getLastUsedAt());
        
        // 验证发布了模板变更事件
        verify(eventPublisher).publishEvent(any(TemplateChangeEvent.class));
    }

    @Test
    @DisplayName("设置当前模板 - 更新现有设置")
    void testSetCurrentTemplate_Update() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);
        when(preferenceMapper.updateByHrUserId(any(HrTemplatePreference.class))).thenReturn(1);

        // When
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-3001");

        // Then
        ArgumentCaptor<HrTemplatePreference> captor = ArgumentCaptor.forClass(HrTemplatePreference.class);
        verify(preferenceMapper).selectByHrUserId("hr-1001");
        verify(preferenceMapper).updateByHrUserId(captor.capture());
        
        HrTemplatePreference updated = captor.getValue();
        assertEquals("tmpl-3001", updated.getTemplateId());
        assertNotNull(updated.getUpdatedAt());
        assertNotNull(updated.getLastUsedAt());
        
        // 验证发布了模板变更事件
        ArgumentCaptor<TemplateChangeEvent> eventCaptor = ArgumentCaptor.forClass(TemplateChangeEvent.class);
        verify(eventPublisher).publishEvent(eventCaptor.capture());
        
        TemplateChangeEvent event = eventCaptor.getValue();
        assertEquals("hr-1001", event.getHrUserId());
        assertEquals("ent-1", event.getEnterpriseId());
        assertEquals("tmpl-2001", event.getOldTemplateId());
        assertEquals("tmpl-3001", event.getNewTemplateId());
    }

    @Test
    @DisplayName("设置当前模板 - 切换到默认模板")
    void testSetCurrentTemplate_SwitchToDefault() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);
        when(preferenceMapper.updateByHrUserId(any(HrTemplatePreference.class))).thenReturn(1);

        // When
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", null);

        // Then
        ArgumentCaptor<HrTemplatePreference> captor = ArgumentCaptor.forClass(HrTemplatePreference.class);
        verify(preferenceMapper).updateByHrUserId(captor.capture());
        
        HrTemplatePreference updated = captor.getValue();
        assertNull(updated.getTemplateId());
        
        // 验证发布了模板变更事件（从自定义切换到默认）
        verify(eventPublisher).publishEvent(any(TemplateChangeEvent.class));
    }

    @Test
    @DisplayName("设置当前模板 - 相同模板不发布事件")
    void testSetCurrentTemplate_SameTemplate() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);
        when(preferenceMapper.updateByHrUserId(any(HrTemplatePreference.class))).thenReturn(1);

        // When - 设置相同的模板ID
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-2001");

        // Then
        verify(preferenceMapper).updateByHrUserId(any(HrTemplatePreference.class));
        // 相同模板不应发布变更事件
        verify(eventPublisher, never()).publishEvent(any(TemplateChangeEvent.class));
    }

    @Test
    @DisplayName("设置当前模板 - 两个null视为相同")
    void testSetCurrentTemplate_BothNull() {
        // Given
        preference.setTemplateId(null);
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);
        when(preferenceMapper.updateByHrUserId(any(HrTemplatePreference.class))).thenReturn(1);

        // When - 设置为null（与当前的null相同）
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", null);

        // Then
        verify(preferenceMapper).updateByHrUserId(any(HrTemplatePreference.class));
        // 都是null，不应发布变更事件
        verify(eventPublisher, never()).publishEvent(any(TemplateChangeEvent.class));
    }

    @Test
    @DisplayName("设置当前模板 - 从默认切换到自定义")
    void testSetCurrentTemplate_FromDefaultToCustom() {
        // Given
        preference.setTemplateId(null);
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);
        when(preferenceMapper.updateByHrUserId(any(HrTemplatePreference.class))).thenReturn(1);

        // When
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-3001");

        // Then
        verify(preferenceMapper).updateByHrUserId(any(HrTemplatePreference.class));
        
        ArgumentCaptor<TemplateChangeEvent> eventCaptor = ArgumentCaptor.forClass(TemplateChangeEvent.class);
        verify(eventPublisher).publishEvent(eventCaptor.capture());
        
        TemplateChangeEvent event = eventCaptor.getValue();
        assertNull(event.getOldTemplateId());
        assertEquals("tmpl-3001", event.getNewTemplateId());
    }

    @Test
    @DisplayName("设置当前模板 - 异常处理")
    void testSetCurrentTemplate_Exception() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001"))
            .thenThrow(new RuntimeException("数据库连接失败"));

        // When & Then
        assertThrows(RuntimeException.class, () -> {
            preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-2001");
        });
        
        // 异常时不应发布事件
        verify(eventPublisher, never()).publishEvent(any());
    }

    @Test
    @DisplayName("设置当前模板 - 插入失败但不影响事件发布")
    void testSetCurrentTemplate_InsertFailed() {
        // Given
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(null);
        when(preferenceMapper.insert(any(HrTemplatePreference.class))).thenReturn(0);

        // When
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-2001");

        // Then
        verify(preferenceMapper).insert(any(HrTemplatePreference.class));
        // 即使插入返回0，也应该发布事件
        verify(eventPublisher).publishEvent(any(TemplateChangeEvent.class));
    }

    @Test
    @DisplayName("设置当前模板 - 更新lastUsedAt时间")
    void testSetCurrentTemplate_UpdateLastUsedAt() {
        // Given
        LocalDateTime oldLastUsedAt = LocalDateTime.now().minusDays(7);
        preference.setLastUsedAt(oldLastUsedAt);
        when(preferenceMapper.selectByHrUserId("hr-1001")).thenReturn(preference);
        when(preferenceMapper.updateByHrUserId(any(HrTemplatePreference.class))).thenReturn(1);

        // When
        LocalDateTime beforeCall = LocalDateTime.now();
        preferenceService.setCurrentTemplate("hr-1001", "ent-1", "tmpl-3001");
        LocalDateTime afterCall = LocalDateTime.now();

        // Then
        ArgumentCaptor<HrTemplatePreference> captor = ArgumentCaptor.forClass(HrTemplatePreference.class);
        verify(preferenceMapper).updateByHrUserId(captor.capture());
        
        HrTemplatePreference updated = captor.getValue();
        // lastUsedAt应该在调用前后之间
        assertTrue(updated.getLastUsedAt().isAfter(beforeCall.minusSeconds(1)));
        assertTrue(updated.getLastUsedAt().isBefore(afterCall.plusSeconds(1)));
    }
}
